/*
 * ASTLiteral.java - ScriptME
 * 
 * Copyright (c) 2009 Cesar Henriques <cesar at alttab.com.ar>.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser Public License v2.1
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * 
 * Based on FESI Project
 * 
 * Contributors:
 * 	Jean-Marc Lugrin - initial API and implementation
 * 	Cesar Henriques <cesar at alttab.com.ar> - J2ME Porting and Extensions
 */
/*
 * 
 */

package org.scriptme.ecmascript.ast;

import org.scriptme.ecmascript.data.ESBoolean;
import org.scriptme.ecmascript.data.ESNull;
import org.scriptme.ecmascript.data.ESUndefined;
import org.scriptme.ecmascript.data.ESNumber;
import org.scriptme.ecmascript.data.ESString;
import org.scriptme.ecmascript.data.ESValue;
import org.scriptme.ecmascript.exceptions.ProgrammingError;
import org.scriptme.ecmascript.parser.EcmaScript;

// TODO: Auto-generated Javadoc
/**
 * The Class ASTLiteral.
 */
public class ASTLiteral extends SimpleNode {

	/** The value. */
	private ESValue theValue = null;

	/**
	 * Instantiates a new aST literal.
	 * 
	 * @param id
	 *            the id
	 */
	public ASTLiteral(int id) {
		super(id);
	}

	/**
	 * Instantiates a new aST literal.
	 * 
	 * @param p
	 *            the p
	 * @param id
	 *            the id
	 */
	public ASTLiteral(EcmaScript p, int id) {
		super(p, id);
	}

	/**
	 * Jjt create.
	 * 
	 * @param id
	 *            the id
	 * 
	 * @return the node
	 */
	public static Node jjtCreate(int id) {
		return new ASTLiteral(id);
	}

	/**
	 * Jjt create.
	 * 
	 * @param p
	 *            the p
	 * @param id
	 *            the id
	 * 
	 * @return the node
	 */
	public static Node jjtCreate(EcmaScript p, int id) {
		return new ASTLiteral(p, id);
	}

	/**
	 * Accept the visitor. *
	 * 
	 * @param visitor
	 *            the visitor
	 * @param data
	 *            the data
	 * 
	 * @return the object
	 */
	public Object jjtAccept(EcmaScriptVisitor visitor, Object data) {
		return visitor.visit(this, data);
	}

	// JMCL
	/**
	 * Gets the value.
	 * 
	 * @return the value
	 */
	public ESValue getValue() {
		return theValue;
	}

	/**
	 * Hexval.
	 * 
	 * @param c
	 *            the c
	 * 
	 * @return the int
	 * 
	 * @throws ProgrammingError
	 *             the programming error
	 */
	static final int hexval(char c) throws ProgrammingError {
		switch (c) {
		case '0':
			return 0;
		case '1':
			return 1;
		case '2':
			return 2;
		case '3':
			return 3;
		case '4':
			return 4;
		case '5':
			return 5;
		case '6':
			return 6;
		case '7':
			return 7;
		case '8':
			return 8;
		case '9':
			return 9;

		case 'a':
		case 'A':
			return 10;
		case 'b':
		case 'B':
			return 11;
		case 'c':
		case 'C':
			return 12;
		case 'd':
		case 'D':
			return 13;
		case 'e':
		case 'E':
			return 14;
		case 'f':
		case 'F':
			return 15;
		}

		throw new ProgrammingError("Illegal hex or unicode constant"); // Should
																		// never
																		// come
																		// here
	}

	/**
	 * Octval.
	 * 
	 * @param c
	 *            the c
	 * 
	 * @return the int
	 * 
	 * @throws ProgrammingError
	 *             the programming error
	 */
	static final int octval(char c) throws ProgrammingError {
		switch (c) {
		case '0':
			return 0;
		case '1':
			return 1;
		case '2':
			return 2;
		case '3':
			return 3;
		case '4':
			return 4;
		case '5':
			return 5;
		case '6':
			return 6;
		case '7':
			return 7;
		case '8':
			return 8;
		case '9':
			return 9;

		case 'a':
		case 'A':
			return 10;
		case 'b':
		case 'B':
			return 11;
		case 'c':
		case 'C':
			return 12;
		case 'd':
		case 'D':
			return 13;
		case 'e':
		case 'E':
			return 14;
		case 'f':
		case 'F':
			return 15;
		}

		throw new ProgrammingError("Illegal octal constant"); // Should never
																// come here
	}

	/**
	 * Sets the string value.
	 * 
	 * @param image
	 *            the new string value
	 */
	public void setStringValue(String image) {
		int l = image.length();
		StringBuffer sb = new StringBuffer(l);
		for (int i = 0; i < l; i++) {
			char c = image.charAt(i);
			if ((c == '\\') && (i + 1 < l)) {
				i++;
				c = image.charAt(i);
				if (c == 'n')
					c = '\n';
				else if (c == 'b')
					c = '\b';
				else if (c == 'f')
					c = '\f';
				else if (c == 'r')
					c = '\r';
				else if (c == 't')
					c = '\t';
				else if (c == 'x') {
					c = (char) (hexval(image.charAt(i + 1)) << 4 | hexval(image
							.charAt(i + 1)));
					i += 2;
				} else if (c == 'u') {
					c = (char) (hexval(image.charAt(i + 1)) << 12
							| hexval(image.charAt(i + 2)) << 8
							| hexval(image.charAt(i + 3)) << 4 | hexval(image
							.charAt(i + 4)));
					i += 4;
				} else if (c >= '0' && c <= '7') {
					c = (char) (octval(image.charAt(i)));
					if ((image.length() > i) && (image.charAt(i + 1) >= '0')
							&& (image.charAt(i + 1) <= '7')) {
						i++;
						c = (char) ((c << 4) | octval(image.charAt(i)));
					}
				}
			}
			sb.append(c);
		}
		theValue = new ESString(sb.toString());
	}

	/**
	 * Sets the decimal value.
	 * 
	 * @param image
	 *            the new decimal value
	 */
	public void setDecimalValue(String image) {
		try {
			theValue = new ESNumber(Long.parseLong(image));
		} catch (NumberFormatException e) {
			theValue = new ESNumber(Double.valueOf(image).doubleValue());
		}
	}

	/**
	 * Sets the octal value.
	 * 
	 * @param image
	 *            the new octal value
	 */
	public void setOctalValue(String image) {
		try {
			String imageWithout0 = image.substring(1);
			theValue = new ESNumber(Long.parseLong(imageWithout0, 8));
		} catch (NumberFormatException e) {
			theValue = new ESNumber(Double.valueOf(image).doubleValue());
		}
	}

	/**
	 * Sets the hex value.
	 * 
	 * @param image
	 *            the new hex value
	 */
	public void setHexValue(String image) {
		try {
			String imageWithout0x = image.substring(2);
			theValue = new ESNumber(Long.parseLong(imageWithout0x, 16));
		} catch (NumberFormatException e) {
			theValue = new ESNumber(Double.valueOf(image).doubleValue());
		}
	}

	/**
	 * Sets the floating point value.
	 * 
	 * @param image
	 *            the new floating point value
	 */
	public void setFloatingPointValue(String image) {
		theValue = new ESNumber(Double.valueOf(image).doubleValue());
	}

	/**
	 * Sets the boolean value.
	 * 
	 * @param value
	 *            the new boolean value
	 */
	public void setBooleanValue(boolean value) {
		theValue = ESBoolean.makeBoolean(value);
	}

	/**
	 * Sets the null value.
	 */
	public void setNullValue() {
		theValue = ESNull.theNull;
	}

	/**
	 * Sets the undefined value.
	 */
	public void setUndefinedValue() {
		theValue = ESUndefined.theUndefined;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.scriptme.ecmascript.ast.SimpleNode#toString()
	 */
	public String toString() {
		return "[" + theValue.toString() + "]";
	}
}
